using System.Text;

using Microsoft.Build.Utilities;
using Xamarin.Android.Tools;

namespace Xamarin.Android.Tasks
{
	class NdkToolsWithClangWithPlatforms : NdkToolsWithClang
	{
		public NdkToolsWithClangWithPlatforms (string androidNdkPath, NdkVersion version, TaskLoggingHelper? log)
			: base (androidNdkPath, version, log)
		{
			NeedClangWorkaround = IsWindows && Version.Main.Major >= 19;
			if (NeedClangWorkaround) {
				//
				// NDK r19 bug (fixed in r19c).
				//
				// The llvm toolchain directory contains a selection of shell scripts (both Unix and Windows)
				// which call `clang/clang++` with different `-target` parameters depending on both the target
				// architecture and API level. For instance, the clang/clang++ compilers targetting aarch64 on API level
				// 28 will have the following Unix shell scripts present in the toolchain `bin` directory:
				//
				//   aarch64-linux-android28-clang
				//   aarch64-linux-android28-clang++
				//
				// However, the Windows version of the NDK has a bug where there is only one  Windows
				// counterpart to the above Unix scripts:
				//
				//   aarch64-linux-android28-clang.cmd
				//
				// This script, despite its name suggesting that it calls `clang.exe` in fact calls
				// `clang++.exe` which breaks compilation of some C programs (including the code generated by
				// Mono's mkbundle utility) because `clang++` treats the input as C++. There is no corresponding
				// `aarch64-linux-android28-clang++.cmd` and so invocation of `clang.exe` becomes harder and,
				// most certainly, non-standard as far as cross-platform NDK compatibility is concerned.
				//
				// The code below tries to rectify the situation by special-casing the compiler tool handling to
				// return path to the actual .exe instead of the CMD.
				//
				// Despite the above issue having been fixed in NDK r19c, the CMD scripts in question have another issue -
				// they don't work well with paths that have spaces in them. That means we either need to quote the paths
				// ourselves, or invoke the compilers directly.  The latter option seems to be the better one.
				//
				NdkToolNames[NdkToolKind.CompilerC] = "clang.exe";
				NdkToolNames[NdkToolKind.CompilerCPlusPlus] = "clang++.exe";
			}
		}

		public override string GetCompilerTargetParameters (AndroidTargetArch arch, int apiLevel, bool forCPlusPlus = false)
		{
			if (!NeedClangWorkaround) {
				return base.GetCompilerTargetParameters (arch, apiLevel, forCPlusPlus);
			}

			var sb = new StringBuilder ();
			sb.Append ("--target=").Append (GetCompilerTriple (arch)).Append (apiLevel);
			sb.Append (" -fno-addrsig");

			if (arch == AndroidTargetArch.X86) {
				sb.Append (" -mstackrealign");
			}

			if (forCPlusPlus) {
				sb.Append (" -stdlib=libc++");
			}

			return sb.ToString ();
		}
	}
}
